import math

from rpy2.rlike.container import OrdDict
from rpy2.robjects import default_converter, pandas2ri
import rpy2.robjects as robjects
from rpy2.robjects.conversion import localconverter
import pandas as pd
from utils.analysis.common.mediation_common_class import SEMResult, CFAResultFi, SEMResultFactorDetails, \
    SEMResultFactor, SEMRelationConfig

# pandas2ri.activate()

# 定义R语言脚本-结构方程
r_script = """
    func_cfa <- function(data, model) {
        library(lavaan)
        #library(semPlot)

        # 拟合SEM, estimator：最小二乘（"ML"）、最小二乘法（"WLS"）和广义最小二乘法（"GLS"）。
        fit <- sem(model, data=data,estimator="ML")

        # 提取结果
        summary_res <- summary(fit, standardized=TRUE)

        # 验证结果的准确性
        # res = fitMeasures(fit)
        fi_res <- fitMeasures(fit, c("chisq","df","nfi","rfi","ifi","tli","cfi","gfi","rmsea"))

        result_list <- list(summary_res = summary_res, fi_res = fi_res)
        result_list
        
    }
    """


def define_model(var_dict: dict, relations: [SEMRelationConfig]):
    # 动态构建模型字符串
    # cur_str = "# 测量模型\n"
    cur_str = ""
    for k, v in var_dict.items():
        cur_str += f"{k} =~ {' + '.join(v)}\n"
    cur_str += f"\n"
    for i in relations:
        cur_str += f"{i.to_name} ~ {i.from_name}\n"
    print(cur_str)  # 打印模型字符串
    return cur_str


class SEM:
    def __init__(self, df, var_dict, relations):
        self.df = df
        self.var_dict = var_dict
        self.relations = relations

    def analysis(self) -> SEMResult:
        with localconverter(default_converter + pandas2ri.converter):
            # 将Python的DataFrame转换为R的DataFrame
            r_df = pandas2ri.py2rpy(self.df)
            model = define_model(self.var_dict, self.relations)
            # 将R语言脚本加载到R环境中
            robjects.r(r_script)
            result = robjects.r['func_cfa'](r_df, model)
            fi_res = result.get('fi_res')
            # 计算表1数据
            if len(fi_res) == 9:
                cmin = fi_res[0]
                df_value = fi_res[1]
                cmin_df = fi_res[0] / fi_res[1]
                nfi = fi_res[2]
                rfi = fi_res[3]
                ifi = fi_res[4]
                tli = fi_res[5]
                cfi = fi_res[6]
                gfi = fi_res[7]
                rmsea = fi_res[8]
                fi_obj = CFAResultFi(cmin=cmin, df_value=df_value, cmin_df=cmin_df, nfi=nfi, rfi=rfi, ifi=ifi, tli=tli,
                                     cfi=cfi, gfi=gfi, rmsea=rmsea)
            summary_res = result.get('summary_res')
            pe_df = summary_res.get('pe')
            # 计算表2数据
            item_dict = dict()
            cur_relations = self.relations
            for i, value in enumerate(cur_relations):
                from_name = value.from_name
                to_name = value.to_name
                key = from_name + '~' + to_name
                filtered_df = pe_df[(pe_df['lhs'] == from_name) & (pe_df['op'] == "~") & (pe_df['rhs'] == to_name)]
                if filtered_df.empty:
                    continue
                cur_row = filtered_df.iloc[0]
                item_dict[key] = SEMResultFactorDetails(from_name=from_name, to_name=to_name, est=cur_row['est'],
                                                        se=cur_row['se'], z=cur_row['z'], std_all=cur_row['std.all'],
                                                        p=cur_row['pvalue'])
            # 3. 组装返回参数
            return SEMResult(fi_value=fi_obj, item_dict=item_dict)


if __name__ == '__main__':
    pd.set_option('expand_frame_repr', False)
    df = pd.read_excel('./test_datas.xlsx')
    v_dict = dict()
    v_dict['F1'] = ["JG1", "JG2", "JG3", "JG4", "JG5"]
    v_dict['F2'] = ["XW1", "XW2", "XW3", "XW4"]
    v_dict['F3'] = ["JX1", "JX2", "JX3"]
    v_dict['F4'] = ["YY1", "YY2", "YY3"]
    X = ["F1", "F3"]  # 自遍历那个
    Y = ["F4"]  # 因变量
    M = ["F2"]  # 中介
    relations = list()

    for m in M:
        for x in X:
            relations.append(SEMRelationConfig(m, x))
    for y in Y:
        for x in X:
            relations.append(SEMRelationConfig(y, x))
    for y in Y:
        for m in M:
            relations.append(SEMRelationConfig(y, m))
    obj = SEM(df, v_dict, relations)
    result = obj.analysis()
    print(result)
